#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;

typedef long long ll;

const double eps = 1e-9;
const int N = 60;

bool Eq(double a, double b)
{
	return fabs(a - b) < eps;
}

bool Ls(double a, double b)
{
	return a < b && !Eq(a, b);
}

bool LsEq(double a, double b)
{
	return a < b || Eq(a, b);
}

bool Gr(double a, double b)
{
	return a > b && !Eq(a, b);
}

bool GrEq(double a, double b)
{
	return a > b || Eq(a, b);
}

double mySqrt(double a)
{
	if (Ls(a, 0))
		throw;
	if (a < 0)
		return 0;
	return sqrt(a);
}

struct Point
{
	double x, y;
	Point () {}
	Point (double _x, double _y) : x(_x), y(_y) {}
	Point operator + (Point a)
	{
		return Point(x + a.x, y + a.y);
	}
	Point operator - (Point a)
	{
		return Point(x - a.x, y - a.y);
	}
	Point operator * (double k)
	{
		return Point(x * k, y * k);
	}
	Point operator / (double k)
	{
		return Point(x / k, y / k);
	}
	double operator * (Point a)
	{
		return x * a.y - y * a.x;
	}
	double operator % (Point a)
	{
		return x * a.x + y * a.y;
	}
	bool operator < (const Point &a) const
	{
		return Ls(x, a.x) || (Eq(x, a.x) && Ls(y, a.y));
	}
	double len()
	{
		return mySqrt(x * x + y * y);
	}
	void scan()
	{
		scanf("%lf %lf", &x, &y);
	}
	void print()
	{
		printf("%lf %lf\n", x, y);
	}
};

bool on[N];
bool used[N];
int cnt[N];
int color[N];
vector <int> g[N];
Point p[N][N];
int n;
ll maskEdge[N];
int listComp[N];
bool usedG[N];
int indVertex = 0;

bool onLine(Point A, Point v, Point P)
{
	return Eq((P - A) * v, 0);
}

double getLenIntersect(Point A, Point B, Point C, Point D)
{
	if (!Eq((B - A) * (D - C), 0))
		return 0.0;
	if (!onLine(A, B - A, C))
		return 0.0;
	Point R = min(max(A, B), max(C, D));
	Point L = max(min(A, B), min(C, D));
	if (L < R)
		return (R - L).len();
	return 0.0;
}

bool isTanget(int a, int b)
{
	for (int i = 0; i < cnt[a]; i++)
	{
		Point A = p[a][i];
		Point B = p[a][(i + 1) % cnt[a]];
		for (int s = 0; s < cnt[b]; s++)
		{
			Point C = p[b][s];
			Point D = p[b][(s + 1) % cnt[b]];
			if (Gr(getLenIntersect(A, B, C, D), 0))
				return true;
		}
	}
	return false;
}

void addEdge(int a, int b)
{
	g[a].push_back(b);
	g[b].push_back(a);
}

void deleteVertex(int v)
{
	for (int i = 0; i < (int)g[v].size(); i++)
	{
		int to = g[v][i];
		g[to].erase(find(g[to].begin(), g[to].end(), v));
	}
}

void deleteVertices()
{
	while (1)
	{
		bool change = false;
		for (int i = 0; i < n; i++)
		{
			if (g[i].size() < 3 && g[i].size() > 0)
			{
				deleteVertex(i);
				g[i].clear();
				change = true;
			}
		}
		if (!change)
			break;
	}
}

bool dfs(int v, int cc)
{
	color[v] = cc;
	int nc = (cc == 1 ? 2 : 1);
	for (int i = 0; i < (int)g[v].size(); i++)
	{
		int to = g[v][i];
		if (on[to])
			continue;
		if (color[to] == 0)
		{
			if (!dfs(to, nc))
				return false;
		}
		else if (color[to] != nc)
			return false;
	}
	return true;
}

bool bipGraph()
{
	memset(color, 0, sizeof(color));
	for (int i = 0; i < n; i++)
	{
		if (!color[i] && !on[i])
			if (!dfs(i, 1))
				return false;
	}
	return true;
}

bool checkBip()
{
	for (int i = 0; i < indVertex; i++)
	{
		int v = listComp[i];
		if (on[v] || used[v])
			continue;
		if (!dfs(v, 1))
			return false;
	}
	return true;
}

ll maskSet = 0;

bool brute(int pos, int sz)
{
	if (sz * 3 > indVertex)
		return false;
	if (checkBip())
		return true;
	if (pos == indVertex)
		return false;
	int vertex = listComp[pos];
	on[vertex] = 0;
	if (brute(pos + 1, sz))
		return true;
	if ((maskSet & maskEdge[vertex]) != 0)
		return false;
	
	on[vertex] = 1;

	maskSet ^= (1 << vertex);
	if (brute(pos + 1, sz + 1))
		return true;
	maskSet ^= (1 << vertex);
	on[vertex] = 0;
	
	return false;
}

void getComp(int v)
{
	listComp[indVertex++] = v;
	usedG[v] = 1;
	for (int i = 0; i < (int)g[v].size(); i++)
	{
		int to = g[v][i];
		if (!usedG[to])
			getComp(to);
	}
}

void solve()
{
	bool nonZero = false;
	for (int i = 0; i < n; i++)
	{
		if (g[i].size() > 0)
			nonZero = true;
	}
	if (!nonZero)
	{
		printf("1\n");
		return;
	}
		
	if (bipGraph())
	{
		printf("2\n");
		return;
	}
	
	deleteVertices();
	for (int i = 0; i < n; i++)
	{
		for (int s = 0; s < (int)g[i].size(); s++)
		{
			int to = g[i][s];
			maskEdge[i] |= (1LL << to);
		}
	}
	memset(usedG, 0, sizeof(usedG));
	bool ok = true;
	for (int i = 0; i < n; i++)
	{
		if (g[i].size() > 0 && !usedG[i])
		{
			indVertex = 0;
			getComp(i);
			ok &= brute(0, 0);
		}
	}
	if (ok)
		puts("3");
	else
		printf("4\n");
}

bool read()
{
	memset(on, 0, sizeof(on));
	memset(color, 0, sizeof(color));
	memset(used, 0, sizeof(used));
	memset(maskEdge, 0, sizeof(maskEdge));
	for (int i = 0; i < N; i++)
		g[i].clear();
	maskSet = 0;

	scanf("%d", &n);
	if (n == 0)
		return false;
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &cnt[i]);
		for (int s = 0; s < cnt[i]; s++)
			p[i][s].scan();
	}
	
	for (int a = 0; a < n; a++)
		for (int b = a + 1; b < n; b++)
		{
			if (isTanget(a, b))
			{
				addEdge(a, b);
			}
		}
	
	return true;
}

bool readGraph()
{
	memset(on, 0, sizeof(on));
	memset(color, 0, sizeof(color));
	memset(used, 0, sizeof(used));
	memset(maskEdge, 0, sizeof(maskEdge));
	for (int i = 0; i < N; i++)
		g[i].clear();
	maskSet = 0;

	int m;
	scanf("%d%d", &n, &m);
	if (n == 0)
		return false;
	for (int i = 0; i < m; i++)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		a--, b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	return true;
}
int main()
{
	int test = 0;
	while (read())
	{
		solve();
	}
	return 0;
}